#include <brpc/channel.h>
#include <vector>
#include <mutex>
#include <unordered_map>
#include <unordered_set>
#include <string>
#include "logger.hpp"
// 1.封装单个服务的信号管理类
class ServiceChannel
{
public:
    ServiceChannel(const std::string &name) : _service_name(name), _index(0)
    {
    }
    using Ptr = std::shared_ptr<ServiceChannel>;
    using Channel_Ptr = std::shared_ptr<brpc::Channel>;
    // 服务上线了一个节点，则调用append新增信道
    void append(const std::string &host)
    {
        auto channel = std::make_shared<brpc::Channel>();
        brpc::ChannelOptions options;
        options.connect_timeout_ms = -1;
        options.timeout_ms = -1;
        options.max_retry = 3;
        options.protocol = "baidu_std";
        if (channel->Init(host.c_str() ,&options) == -1)
        {
            LOG_ERROR("初始化{}-{}信道失败", _service_name, host);
            return;
        }
        std::unique_lock<std::mutex> lock(_mutex);
        _hosts.insert(std::make_pair(host, channel));
        _channels.push_back(channel);
    }
    // 服务下线了一个节点，则调用remove释放信道
    void remove(const std::string &host)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _hosts.find(host);
        if (it == _hosts.end())
        {
            LOG_WARN("{}-{}节点删除信道时，未找到信道信息！", _service_name, host);
            return;
        }
        for (auto iter = _channels.begin(); iter != _channels.end(); ++iter)
        {
            if (*iter == it->second)
            {
                _channels.erase(iter);
                break;
            }
        }
        _hosts.erase(it);
    }
    // 依据RR轮转策略获取一个信道用于发起对应服务的RPC调用
    Channel_Ptr choose()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if (_channels.size() == 0)
        {
            LOG_ERROR("未找到能提供{}服务的节点", _service_name);
            return Channel_Ptr();
        }
        auto res = _channels[(_index++) % _channels.size()];
        return res;
    }

private:
    std::mutex _mutex;
    int32_t _index;                                      // RR轮转计数器
    std::string _service_name;                           // 服务名称
    std::vector<Channel_Ptr> _channels;                  // 当前服务对应的信道集合
    std::unordered_map<std::string, Channel_Ptr> _hosts; // 主机地址与信道的映射关系
};

// 总体的服务信道管理类
class ServiceManager
{
public:
    using Ptr = std::shared_ptr<ServiceManager>;
    // 通过服务名称获取信道
    ServiceChannel::Channel_Ptr choose(const std::string &service_name)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto air_iter = _services.find(service_name);
        if (air_iter == _services.end())
        {
            LOG_ERROR("未找到能提供{}服务的节点", service_name);
            return ServiceChannel::Channel_Ptr();
        }
        return air_iter->second->choose();
    }
    // 关注哪些服务的上下线，不关注的就不需要管理了
    void declared(const std::string &service_name)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _follow_services.insert(service_name);
    }
    // 服务上线时调用的回调接口，将服务节点管理起来
    void OnServiceOnline(const std::string &service_instance, const std::string &host)
    {
        std::string service_name = GetServiceName(service_instance);
        ServiceChannel::Ptr service;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto fit = _follow_services.find(service_name);
            if(fit == _follow_services.end())
            {
                LOG_WARN("尝试访问未设置关心的服务{}",service_name);
                return;
            }
            // 获取管理对象，没有则创建，有则添加节点
            auto air_iter = _services.find(service_name);
            if (air_iter == _services.end())
            {
                service = std::make_shared<ServiceChannel>(service_name);
                _services.insert(std::make_pair(service_name, service));
            }
            else
            {
                service = air_iter->second;
            }
        }
        if (service.get() == nullptr)
        {
            LOG_ERROR("新增{}服务管理节点失败! ", service_name);
        }
        else
        {
            service->append(host);
        }
    }
    // 服务下线时调用的回调接口，删除指定节点信道
    void OnServiceOffline(const std::string &service_instance, const std::string &host)
    {
        std::string service_name = GetServiceName(service_instance);
        ServiceChannel::Ptr service;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto fit = _follow_services.find(service_name);
            if(fit == _follow_services.end())
            {
                LOG_WARN("尝试访问未设置关心的服务{}",service_name);
                return;
            }
            auto air_iter = _services.find(service_name);
            if(air_iter == _services.end())
            {
                LOG_WARN("未找到{}服务信息",service_name);
                return;
            }
            service = air_iter->second;
        }
        service->remove(host);
    }
public:
    std::string GetServiceName(const std::string& instance_name)
    {
        int pos = instance_name.rfind('/');
        if(pos == std::string::npos) return instance_name;
        return instance_name.substr(0,pos);
    }
private:
    std::mutex _mutex;
    std::unordered_set<std::string> _follow_services;               // 关心哪些服务？
    std::unordered_map<std::string, ServiceChannel::Ptr> _services; // 服务对应的实例
};